using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Domain.Entities;
using SumerCoreDevOps.Infrastructure.Data;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;

namespace SumerCoreDevOps.Infrastructure.NodeRegistration;

/// <summary>
/// 节点建立连接令牌管理器（Join Token Manager）
/// 管理用于首次注册的一次性令牌
/// </summary>
public class NodeJoinTokenManager
{
    private readonly FreeSQLProvider _dbProvider;
    private readonly ILogger<NodeJoinTokenManager> _logger;

    public NodeJoinTokenManager(FreeSQLProvider dbProvider, ILogger<NodeJoinTokenManager> logger)
    {
        _dbProvider = dbProvider;
        _logger = logger;
    }

    /// <summary>
    /// 生成建立连接令牌
    /// </summary>
    public async Task<NodeJoinToken> GenerateTokenAsync(
        string? name = null,
        string? description = null,
        int? expiresInHours = 24,
        int? maxUsageCount = 1,
        string? createdBy = null)
    {
        // 生成唯一令牌
        var token = GenerateSecureToken();

        var joinToken = new NodeJoinToken
        {
            Token = token,
            Name = name ?? $"Token_{DateTime.UtcNow:yyyyMMddHHmmss}",
            Description = description,
            ExpiresAt = expiresInHours.HasValue ? DateTime.UtcNow.AddHours(expiresInHours.Value) : null,
            MaxUsageCount = maxUsageCount,
            UsedCount = 0,
            IsEnabled = true,
            IsRevoked = false,
            CreatedAt = DateTime.UtcNow,
            CreatedBy = createdBy
        };

        await _dbProvider.Orm.Insert(joinToken).ExecuteAffrowsAsync();
        _logger.LogInformation("生成节点建立连接令牌: {TokenName}, 有效期: {ExpiresAt}, 最大使用次数: {MaxUsage}",
            joinToken.Name, joinToken.ExpiresAt, joinToken.MaxUsageCount);

        return joinToken;
    }

    /// <summary>
    /// 验证令牌
    /// </summary>
    public async Task<(bool isValid, string? errorMessage, NodeJoinToken? token)> ValidateTokenAsync(string token)
    {
        var joinToken = await _dbProvider.Orm.Select<NodeJoinToken>()
            .Where(t => t.Token == token)
            .FirstAsync();

        if (joinToken == null)
        {
            return (false, "令牌不存在", null);
        }

        if (!joinToken.IsEnabled)
        {
            return (false, "令牌未启用", joinToken);
        }

        if (joinToken.IsRevoked)
        {
            return (false, $"令牌已被撤销: {joinToken.RevokeReason}", joinToken);
        }

        if (joinToken.ExpiresAt.HasValue && joinToken.ExpiresAt.Value < DateTime.UtcNow)
        {
            return (false, "令牌已过期", joinToken);
        }

        if (joinToken.MaxUsageCount.HasValue && joinToken.UsedCount >= joinToken.MaxUsageCount.Value)
        {
            return (false, "令牌已达到最大使用次数", joinToken);
        }

        return (true, null, joinToken);
    }

    /// <summary>
    /// 使用令牌（增加使用次数）
    /// </summary>
    public async Task<bool> UseTokenAsync(string token, long nodeId)
    {
        var (isValid, errorMessage, joinToken) = await ValidateTokenAsync(token);

        if (!isValid || joinToken == null)
        {
            _logger.LogWarning("令牌验证失败: {Token}, 原因: {Error}", token, errorMessage);
            return false;
        }

        // 更新已注册节点列表
        var nodeIds = new List<long>();
        if (!string.IsNullOrEmpty(joinToken.RegisteredNodeIds))
        {
            nodeIds = JsonSerializer.Deserialize<List<long>>(joinToken.RegisteredNodeIds) ?? new List<long>();
        }
        nodeIds.Add(nodeId);

        // 更新令牌使用信息
        joinToken.UsedCount++;
        joinToken.LastUsedAt = DateTime.UtcNow;
        joinToken.RegisteredNodeIds = JsonSerializer.Serialize(nodeIds);
        joinToken.UpdatedAt = DateTime.UtcNow;

        await _dbProvider.Orm.Update<NodeJoinToken>()
            .SetSource(joinToken)
            .ExecuteAffrowsAsync();

        _logger.LogInformation("令牌使用成功: {TokenName}, 已使用次数: {UsedCount}/{MaxCount}, NodeId: {NodeId}",
            joinToken.Name, joinToken.UsedCount, joinToken.MaxUsageCount ?? -1, nodeId);

        return true;
    }

    /// <summary>
    /// 撤销令牌
    /// </summary>
    public async Task RevokeTokenAsync(long tokenId, string reason, string? revokedBy = null)
    {
        var token = await _dbProvider.Orm.Select<NodeJoinToken>()
            .Where(t => t.Id == tokenId)
            .FirstAsync();

        if (token == null)
        {
            throw new InvalidOperationException("令牌不存在");
        }

        if (token.IsRevoked)
        {
            _logger.LogWarning("令牌已被撤销: {TokenId}", tokenId);
            return;
        }

        token.IsRevoked = true;
        token.RevokedAt = DateTime.UtcNow;
        token.RevokeReason = reason;
        token.RevokedBy = revokedBy;
        token.UpdatedAt = DateTime.UtcNow;

        await _dbProvider.Orm.Update<NodeJoinToken>()
            .SetSource(token)
            .ExecuteAffrowsAsync();

        _logger.LogInformation("撤销令牌: {TokenName}, 原因: {Reason}", token.Name, reason);
    }

    /// <summary>
    /// 撤销令牌（通过令牌字符串）
    /// </summary>
    public async Task RevokeTokenByTokenStringAsync(string tokenString, string reason, string? revokedBy = null)
    {
        var token = await _dbProvider.Orm.Select<NodeJoinToken>()
            .Where(t => t.Token == tokenString)
            .FirstAsync();

        if (token == null)
        {
            throw new InvalidOperationException("令牌不存在");
        }

        await RevokeTokenAsync(token.Id, reason, revokedBy);
    }

    /// <summary>
    /// 获取令牌详情
    /// </summary>
    public async Task<NodeJoinToken?> GetTokenAsync(long tokenId)
    {
        return await _dbProvider.Orm.Select<NodeJoinToken>()
            .Where(t => t.Id == tokenId)
            .FirstAsync();
    }

    /// <summary>
    /// 获取令牌详情（通过令牌字符串）
    /// </summary>
    public async Task<NodeJoinToken?> GetTokenByTokenStringAsync(string tokenString)
    {
        return await _dbProvider.Orm.Select<NodeJoinToken>()
            .Where(t => t.Token == tokenString)
            .FirstAsync();
    }

    /// <summary>
    /// 获取所有令牌
    /// </summary>
    public async Task<List<NodeJoinToken>> GetAllTokensAsync(bool includeRevoked = false)
    {
        var query = _dbProvider.Orm.Select<NodeJoinToken>();

        if (!includeRevoked)
        {
            query = query.Where(t => !t.IsRevoked);
        }

        return await query.OrderByDescending(t => t.CreatedAt).ToListAsync();
    }

    /// <summary>
    /// 获取有效令牌
    /// </summary>
    public async Task<List<NodeJoinToken>> GetValidTokensAsync()
    {
        return await _dbProvider.Orm.Select<NodeJoinToken>()
            .Where(t => t.IsEnabled && !t.IsRevoked)
            .Where(t => t.ExpiresAt == null || t.ExpiresAt > DateTime.UtcNow)
            .OrderByDescending(t => t.CreatedAt)
            .ToListAsync();
    }

    /// <summary>
    /// 删除令牌
    /// </summary>
    public async Task DeleteTokenAsync(long tokenId)
    {
        var token = await _dbProvider.Orm.Select<NodeJoinToken>()
            .Where(t => t.Id == tokenId)
            .FirstAsync();

        if (token == null)
        {
            throw new InvalidOperationException("令牌不存在");
        }

        // 检查是否已被使用
        if (token.UsedCount > 0)
        {
            throw new InvalidOperationException("已使用的令牌不允许删除，请使用撤销功能");
        }

        await _dbProvider.Orm.Delete<NodeJoinToken>()
            .Where(t => t.Id == tokenId)
            .ExecuteAffrowsAsync();

        _logger.LogInformation("删除令牌: {TokenName}", token.Name);
    }

    /// <summary>
    /// 生成安全令牌
    /// </summary>
    private string GenerateSecureToken()
    {
        // 生成 32 字节的随机数据
        var randomBytes = RandomNumberGenerator.GetBytes(32);

        // 转换为 Base64 并移除特殊字符
        var token = Convert.ToBase64String(randomBytes)
            .Replace("+", "")
            .Replace("/", "")
            .Replace("=", "");

        // 如果长度超过 48 个字符，截取前 48 个字符
        if (token.Length > 48)
        {
            token = token.Substring(0, 48);
        }

        return token;
    }

    /// <summary>
    /// 生成注册命令（用于执行节点）
    /// </summary>
    public string GenerateRegistrationCommand(string token, string controlPanelUrl, int tcpPort)
    {
        // 生成命令行注册命令
        return $"dotnet run -- --discovery-url={controlPanelUrl} --join-token={token}";
    }

    /// <summary>
    /// 生成注册链接（用于 Web UI 显示）
    /// </summary>
    public string GenerateRegistrationLink(string token, string controlPanelHttpUrl, int? executeNodePort = null)
    {
        // 生成指向 ExecuteNodeApi 的 HTTP 注册链接
        // 用户在 ExecuteNodeApi 服务器上访问这个链接即可完成注册
        var port = executeNodePort ?? 5288; // ExecuteNodeApi 默认端口

        // 编码参数
        var encodedMaster = Uri.EscapeDataString(controlPanelHttpUrl);
        var encodedToken = Uri.EscapeDataString(token);

        return $"http://localhost:{port}/api/registration/register?master={encodedMaster}&token={encodedToken}";
    }

    /// <summary>
    /// 清理过期令牌
    /// </summary>
    public async Task<int> CleanupExpiredTokensAsync(int daysOld = 30)
    {
        var cutoffDate = DateTime.UtcNow.AddDays(-daysOld);

        var deleted = await _dbProvider.Orm.Delete<NodeJoinToken>()
            .Where(t => t.ExpiresAt < cutoffDate && t.UsedCount == 0)
            .ExecuteAffrowsAsync();

        if (deleted > 0)
        {
            _logger.LogInformation("清理过期令牌: Count={Count}, DaysOld={Days}", deleted, daysOld);
        }

        return (int)deleted;
    }
}
